package edu.upc.dew.filter;

import edu.upc.dew.dto.FormResponse;
import edu.upc.dew.service.AccountService;
import edu.upc.dew.service.exception.BusinessException;
import edu.upc.dew.util.CustomObjectMapper;
import edu.upc.dew.util.KeycodeManager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;

/**
 * Checks the validity of the keycode and loads required user data
 *
 */
public class KeyCodeCheckFilter extends OncePerRequestFilter {

    private static final String KEYCODE_PARAMETER = "keycode";

    private Properties appProperties;
    private List<String> excludedArray;
    private static Map<String, String> keycodeMap = new HashMap<String, String>();

    private AccountService accountService;

    @Override
    protected void initFilterBean() throws ServletException {
        WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        this.appProperties = (Properties) context.getBean("appProperties");
        this.accountService = (AccountService) context.getBean("accountService");
        String excludeUrlProp = appProperties.getProperty("filter.exclude.path");
        excludedArray = new ArrayList<String>();

        if (excludeUrlProp != null && !excludeUrlProp.trim().isEmpty()) {
            StringTokenizer st = new StringTokenizer(excludeUrlProp, ",");

            while (st.hasMoreTokens()) {
                String url = (String) st.nextToken().trim();
                excludedArray.add(url);
            }
        }
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        boolean requestAuthorized = false;
        HttpServletRequestWrapper reqWrap = null;

        String path = request.getRequestURI().substring(request.getContextPath().length());
        if (excludedArray.contains(path)) {
            requestAuthorized = true;
        }

        if (!requestAuthorized) {
            String keycode = request.getParameter(KEYCODE_PARAMETER);
            if (keycode != null && !keycode.trim().equals("")) {
                try {
                    String accountId = KeycodeManager.getKey(keycode);
                    if (keycodeMap.get(accountId) == null || ((String)keycodeMap.get(accountId) != null && keycode.compareTo((String)keycodeMap.get(accountId)) != 0)) {
                        serializeToJSONResponse(response, new FormResponse(false, "KeycodeFilter: Hubo una diferencia entre keycodes: keycode="+keycode+", keycodeMap="+keycodeMap.get(accountId), true));
                        return;
                    }

                    Map<String, String[]> addParam = new HashMap<String, String[]>();
                    reqWrap = new MyHttpServletRequestWrapper(request, addParam);
                    requestAuthorized = true;
                } catch (NumberFormatException e) {
                    serializeToJSONResponse(response, new FormResponse(false, "Parametro numerico en formato incorrecto", true));
                    return;
                } catch (BusinessException e) {
                    serializeToJSONResponse(response, new FormResponse(false, "La sesion expiro, por favor ingresa nuevamente", true));
                    return;
                }
            } else {
                logger.info("KeycodeFilter: No se proporciono ningun Keycode");
            }
        }

        if (requestAuthorized) {
            if (reqWrap == null) {
                filterChain.doFilter(request, response);
            } else {
                filterChain.doFilter(reqWrap, response);
            }
        } else {
            serializeToJSONResponse(response, new FormResponse(false, "Los servicios no esta habilitado para el usuario actual", true));
        }
    }

    private void serializeToJSONResponse(HttpServletResponse response, Object obj) throws IOException {
        response.setContentType("application/json");
        ObjectMapper mapper = new CustomObjectMapper();
        mapper.writeValue(response.getWriter(), obj);
        response.getWriter().flush();
        response.getWriter().close();
    }

    public static void registerKeycode(String id, String keycode) {
        keycodeMap.put(id, keycode);
    }

    public static void unregisterKeycode(String id) {
        keycodeMap.remove(id);
    }
}
